package ca.seia.comp6521.a2.itemsetalgorithms;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

import ca.seia.comp6521.a2.io.DataFileReader;
import ca.seia.comp6521.a2.io.DataFileWriter;
import ca.seia.comp6521.a2.io.FileReadResult;
import ca.seia.comp6521.a2.itemsetstorage.CharItems;
import ca.seia.comp6521.a2.itemsetstorage.CharTriples;
import ca.seia.comp6521.a2.itemsetstorage.IntItemCountStorage;
import ca.seia.comp6521.a2.itemsetstorage.IntItems;
import ca.seia.comp6521.a2.itemsetstorage.TriangularMatrix;
import ca.seia.comp6521.a2.itemsetstorage.Triples;

public class Apriori {
	
	public static final String RESULTS_FILE_PATH = "c:\\Temp\\results.txt";
	public File transactionFile;
	private DataFileWriter fileWriter;
	public int supportPercentage;
	public int support;
	
	public Apriori(File transactionFile,DataFileWriter fileWriter, int supportPercentage) throws IOException {
		this.transactionFile = transactionFile;
		this.supportPercentage = supportPercentage;
		this.fileWriter = fileWriter;
	}
	
	public Apriori(File transactionFile, int supportPercentage) throws IOException {
		this.transactionFile = transactionFile;
		this.supportPercentage = supportPercentage;
		this.fileWriter = new DataFileWriter(RESULTS_FILE_PATH);
	}
	
	public void getFrequentItemSets() throws IOException {
		PassIResult passIResults = executePassI();
		
		if (passIResults.getBitVector().getNbrFrequentItems() < 2) {
			return;
		}
		
		PassIIResult passIIResult = executePassII(passIResults);
		if (passIIResult.getCandidateTriplets().isEmpty()) {
			return;
		} 
		PassNResult passIIIResult = executePassIII(passIIResult);
		if (passIIIResult.getCandidateFrequentItems().isEmpty()) {
			return;
		}
		PassNResult previousPassResult = passIIIResult;
		
		do {
			previousPassResult = executePassN(previousPassResult);
		} while (!previousPassResult.getCandidateFrequentItems().isEmpty());
	}

	public PassIResult executePassI() throws FileNotFoundException {
		DataFileReader passReader = new DataFileReader(transactionFile.getAbsolutePath());
		long startTime = System.currentTimeMillis();
		FileReadResult readResults = passReader.readTransactions();
		
//		System.out.println(readResults); //TODO comment 
		int support = calculateSupport(supportPercentage, readResults.getTransactionCount());
		this.support = support;
		BitVector bitVector = generateBitVector(readResults.getItemCount(), support);
		System.out.println("support " + support); //TODO comment
//		System.out.println(bitVector); //TODO comment 
		long executionTime = System.currentTimeMillis() - startTime;
		return new PassIResult(support, readResults.getItemCount(),executionTime,bitVector);
	}
	
	public PassIIResult executePassII(PassIResult passIResults) throws IOException {
		DataFileReader passReader = new DataFileReader(transactionFile.getAbsolutePath());
		Triples storage = new Triples();
		long startTime = System.currentTimeMillis();
		System.out.println("Doing phase II");
		passReader.readTransactions(passIResults, storage);
//		System.out.println("Candidates pairs " + storage);
//		storage.removeInfrequentPairs(passIResults.getSupport());
//		storage.writeToDisk(passIResults.getSupport(), new DataFileWriter(RESULTS_FILE_PATH));
		storage.removeInfrequentPairsAndWriteToDisk(passIResults.getSupport(), fileWriter);
		List<IntItems> candidateTriplets = storage.generateCandidateTriplets();
//		System.out.println("candidateTriplets are " + candidateTriplets);
		storage = null;
		long executionTime = System.currentTimeMillis() - startTime;
//		System.out.println("Real Frequent pairs " + storage );
		return new PassIIResult(candidateTriplets, executionTime);
	}
	
	public PassIIResult executeCharPassII(PassIResult passIResults) throws IOException {
		DataFileReader passReader = new DataFileReader(transactionFile.getAbsolutePath());
		CharTriples storage = new CharTriples();
		long startTime = System.currentTimeMillis();
		passReader.readTransactions(passIResults, storage);
//		System.out.println("Candidates pairs " + storage);
//		storage.removeInfrequentPairs(passIResults.getSupport());
//		storage.writeToDisk(passIResults.getSupport(), new DataFileWriter(RESULTS_FILE_PATH));
		storage.removeInfrequentPairsAndWriteToDisk(passIResults.getSupport(), fileWriter);
		List<CharItems> candidateTriplets = storage.generateCandidateTriplets();
//		System.out.println("candidateTriplets are " + candidateTriplets);
		storage = null;
		long executionTime = System.currentTimeMillis() - startTime;
//		System.out.println("Real Frequent pairs " + storage );
		return null;
//		return new PassIIResult(candidateTriplets, executionTime);
	}
	
	
	public PassNResult executePassIII(PassIIResult passIIResult) throws IOException {
		DataFileReader passReader = new DataFileReader(transactionFile.getAbsolutePath());
		IntItemCountStorage storageCount = new IntItemCountStorage();
		int nextPassNumber = 4;
		
		passReader.readTransactions(passIIResult, storageCount);
		storageCount.removeInfrequentPairsAndWriteToDisk(this.support, fileWriter);
//		System.out.println(storageCount);
		List<IntItems> candidateFrequentItems = storageCount.generateCandidateFrequentItemsForNextPass(nextPassNumber);
//		System.out.println(candidateFrequentItems);
		storageCount = null;
		return new PassNResult(candidateFrequentItems,0,nextPassNumber);
	}
	
	public PassNResult executePassN(PassNResult previousPassNResult) throws IOException {
		DataFileReader passReader = new DataFileReader(transactionFile.getAbsolutePath());
		IntItemCountStorage storageCount = new IntItemCountStorage();
		int nextPassNumber = previousPassNResult.getPassNumber() + 1;
		
		//System.out.println("Doing pass " + previousPassNResult.getPassNumber());
		//System.out.println("candidte" + previousPassNResult.getCandidateFrequentItems());
		passReader.readTransactions(previousPassNResult, storageCount);
		storageCount.removeInfrequentPairsAndWriteToDisk(this.support, fileWriter);
		List<IntItems> candidateFrequentItems = storageCount.generateCandidateFrequentItemsForNextPass(nextPassNumber);
		storageCount = null;
		return new PassNResult(candidateFrequentItems,0,nextPassNumber);
	}
	
	public BitVector generateBitVector(int[] itemCount,int support) {
		boolean[] bitVector = new boolean[itemCount.length];
		int biggestFrequentItem = -1;
		int previousBiggestFrequentItemCount = 0;
		int nbrFrequentItems = 0;
		for(int item = 0; item < itemCount.length ; item++){
			if (itemCount[item] >= support) {
				bitVector[item] = true;
				nbrFrequentItems++;
				if (previousBiggestFrequentItemCount <= itemCount[item] ) {
					previousBiggestFrequentItemCount = itemCount[item];
					//biggestFrequentItem = item;
				}
				biggestFrequentItem = item;
			} 
		}
		return new BitVector(nbrFrequentItems,biggestFrequentItem, bitVector);
		
	}
	
	public int calculateSupport(double supportPercentange, int numberofTransactions) {
		return (int) ((numberofTransactions * supportPercentange) / 100);
	}

}
